package com.easydemo.easy.service.Impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.easydemo.easy.domain.AppUser;
import com.easydemo.easy.mapper.AppUserMapper;
import com.easydemo.easy.service.AppUserService;
import com.easydemo.easy.vo.AppUserExcelVO;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.FileOutputStream;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * @author :ZhengHao
 * @version :1.0
 * @since :2024-12-27  20:35
 */
@Slf4j
@Service
public class AppUserServiceImpl implements AppUserService {
    @Autowired
    private AppUserMapper appUserMapper;
    @Override
    public List<AppUser> selectAllAppUser() {
        String filePath = "E:\\easyExcelTables\\demo.xlsx";
        try {
            exportUsersToExcel(filePath);
        }catch (Exception exception){
            log.error("exception: {}", exception.getMessage());
        }
        return null;
    }

    @Override
    public Integer insertAppUser() {


        return null;
    }



    /**
     * 导出所有用户数据到指定路径的 Excel 文件。
     *
     * @param filePath 目标文件路径
     * @throws InterruptedException 如果线程被中断
     * @throws ExecutionException   如果任务执行失败
     */
    public void exportUsersToExcel(String filePath) throws InterruptedException, ExecutionException {
        int pageSize = 100_000; // 每页大小
        Long totalRecords = appUserMapper.getTotalRecordCount(); // 获取总记录数的方法

        // 计算需要处理的页数
        int totalPages = (int) Math.ceil((double) totalRecords / pageSize);

        // 创建一个自定义的 ExecutorService
        ExecutorService executor = Executors.newFixedThreadPool(10); // 设置线程池大小为10

        try (FileOutputStream fos = new FileOutputStream(filePath);
             // 构建并获取 ExcelWriter 实例
             ExcelWriter excelWriter = EasyExcel.write(fos, AppUserExcelVO.class).build()) {

            // 创建并提交异步任务

            // 等待所有任务完成
            CompletableFuture.allOf(IntStream.range(0, totalPages)
                    .mapToObj(offsetIndex -> offsetIndex * pageSize) // 将索引转换为偏移量
                    .map(offset -> CompletableFuture.supplyAsync(() -> fetchAndConvertPage(offset, pageSize), executor))
                    .map(future -> future.thenAccept(excelModels -> writeDataToExcel(excelWriter, excelModels))).toArray(CompletableFuture[]::new)).get();

            log.info("All pages processed successfully. Data exported to: {}", filePath);
        } catch (Exception e) {
            log.error("Error exporting users to Excel: {}", e.getMessage());
            throw new RuntimeException("Error exporting users to Excel", e);
        } finally {
            // 关闭 ExecutorService
            shutdownExecutor(executor);
        }
    }

    /**
     * 异步获取并转换一页数据。
     *
     * @param offset  分页偏移量
     * @param size    每页大小
     * @return 转换后的 Excel 数据模型列表
     */
    private List<AppUserExcelVO> fetchAndConvertPage(int offset, int size) {
        try {
            List<AppUser> pageOfUsers = appUserMapper.selectPageOfAppUsers(offset, size);
            log.info("Processing page at offset {}: {} records", offset, pageOfUsers.size());
            return pageOfUsers.stream()
                    .map(AppUser::toExcelModel) // 使用之前定义的转换方法
                    .collect(Collectors.toList());
        } catch (Exception e) {
            throw new RuntimeException("Error processing users at offset " + offset, e);
        }
    }

    /**
     * 将数据写入 Excel 文件。
     *
     * @param excelWriter 已经打开的 ExcelWriter 实例
     * @param data        要写入的数据
     */
    private void writeDataToExcel(ExcelWriter excelWriter, List<AppUserExcelVO> data) {
        try {
            ExcelWriter sheetBuilder = excelWriter.write(data, EasyExcel.writerSheet("Users").build());
            sheetBuilder.finish();
        } catch (Exception e) {
            throw new RuntimeException("Error writing to Excel file", e);
        }
    }

    /**
     * 安全地关闭 ExecutorService。
     *
     * @param executor 要关闭的 ExecutorService
     */
    private void shutdownExecutor(ExecutorService executor) {
        executor.shutdown();
        try {
            if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
                log.warn("Not all tasks completed within the timeout period; attempting to shutdownNow.");
                List<Runnable> notExecutedTasks = executor.shutdownNow();
                log.warn("ShutdownNow called. {} tasks did not execute.", notExecutedTasks.size());

                if (Thread.currentThread().isInterrupted()) {
                    log.error("Current thread was interrupted during shutdown.");
                }
            } else {
                log.info("All tasks completed successfully within the timeout period.");
            }
        } catch (InterruptedException ie) {
            log.error("Interrupted while waiting for termination.", ie);
            executor.shutdownNow();
            Thread.currentThread().interrupt(); // 保留中断状态
        }
    }
}
